﻿using System;
using System.Collections.Generic;
using System.Text;
using taxi_sovereign.model;
using taxi_sovereign.interfaces;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;


namespace taxi_sovereign.view
{
    public static class Painter
    {

        
        static ColorSchema CStemp = new ColorSchema();

        public static ColorSchema ColorSc = new ColorSchema();
        private static int Xs = 0;
        private static int Ys = 0;

        static Model currmodel = new Model();
        static Graphics gr;
        static Bitmap bitmap;
        static Graphics grout;

        static bool busStopText;

        public static void PlusSetXY(int xin, int yin)
        {
            Xs += xin;
            Ys += yin;
        }
        public static int XX()
        {
            return Xs;
        }
        public static int YY()
        {
            return Ys;
        }

        public static bool BusStopText
        {
            get { return Painter.busStopText; }
            set { Painter.busStopText = value; }
        }
        static bool vehicleText;
        public static bool VehicleText
        {
            get { return Painter.vehicleText; }
            set { Painter.vehicleText = value; }
        }

        static Color vehicleColor;
        public static Color VehicleColor
        {
            get { return Painter.vehicleColor; }
            set { Painter.vehicleColor = value; }
        }
        
        static Color crossColor;
        public static Color CrossColor
        {
            get { return Painter.crossColor; }
            set { Painter.crossColor = value; }
        }
        
        static Color roadColor;
        public static Color RoadColor
        {
            get { return Painter.roadColor; }
            set { Painter.roadColor = value; }
        }
        
        static Color stationColor;
        public static Color StationColor
        {
            get { return Painter.stationColor; }
            set { Painter.stationColor = value; }
        }
        
        static Color stopColor;
        public static Color StopColor
        {
            get { return Painter.stopColor; }
            set { Painter.stopColor = value; }
        }
        
        static Color backgroundColor;
        public static Color BackgroundColor
        {
            get { return Painter.backgroundColor; }
            set { Painter.backgroundColor = value; }
        }

        static int vehicleSize = _Constants._vehiclesize;
        public static int VehicleSize
        {
            get { return Painter.vehicleSize; }
            set { Painter.vehicleSize = value; }
        }

        static int roadSize = _Constants._roadsize;
        public static int RoadSize
        {
            get { return Painter.roadSize; }
            set { Painter.roadSize = value; }
        }

        static int crossSize = _Constants._crosssize;
        public static int CrossSize
        {
            get { return Painter.crossSize; }
            set { Painter.crossSize = value; }
        }

        static int stopSize = _Constants._stopsize;
        public static int StopSize
        {
            get { return Painter.stopSize; }
            set { Painter.stopSize = value; }
        }

        static int stationSize;
        public static int StationSize
        {
            get { return Painter.stationSize; }
            set { Painter.stationSize = value; }
        }

        static public void SetGr(Graphics Gr)
        {
            grout = Gr;
            bitmap = new Bitmap(1000, 1000);
            gr = Graphics.FromImage(bitmap);
            gr.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            gr.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
            //gr.RenderingOrigin 
            //ColorSc.VehicleColor = Color.Red;
            //ColorSc.RoadColor = Color.Black;
            //ColorSc.BackgroundColor = Color.LightGray;
            //ColorSc.StopColor = Color.Gold;
            //ColorSc.StationColor = Color.Green;
            //ColorSc.CrossColor = Color.Gray;
            //ColorSc.Chosencolor = Color.Red;
            //ColorSc.Chosenchosencolor = Color.Blue;
            RoadSize = _Constants._roadsize;
            VehicleSize = _Constants._vehiclesize;
            StopSize = _Constants._stopsize;
            CrossSize = _Constants._crosssize;
            //busStopText = true;
            //vehicleText = true;
            stationSize = 5;

        }

        public static void LoadColorSchemaFromFile(string FileName)//Загрузить настройки из файла
        {
            FileStream fs = new FileStream(FileName, FileMode.Open);
            try
            {
                //ColorSchema CSt = new ColorSchema();
                BinaryFormatter formatter = new BinaryFormatter();
                ColorSchema CStemp1 = (ColorSchema)formatter.Deserialize(fs);
                ColorSc = CStemp1;
                //ColorSc.BackgroundColor = CStemp.BackgroundColor;
            }
            catch (SerializationException ex)
            {
                Logger.AddToLog("error while loading " + ex.Message);
                MessageBox.Show("Ошибка: " + ex.Message, "Ошибка",
             MessageBoxButtons.OK, MessageBoxIcon.Warning);
                throw;
            }
            finally
            {
                fs.Close();
            }
        }

        public static void SaveColorSchemaToFile(string FileName)//Сохранить настройки в файл
        {
            FileStream saveFStream = new FileStream(FileName, FileMode.Create);
            IFormatter formatter = new BinaryFormatter();
            try
            {
                formatter.Serialize(saveFStream, ColorSc);
            }
            catch (SerializationException ex)
            {
                Logger.AddToLog("error while saving " + ex.Message);
                MessageBox.Show("Ошибка!" + ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                throw;
            }
            finally
            {
                saveFStream.Close();
            }
        }
        
        static public void SetModel(IModel inputmodel)
        {
            currmodel = (Model)inputmodel;
        }

        static public void RefreshChosen()
        {
            foreach (IRoad r in currmodel.GetModelSettings().Roads())
            {
                foreach (IStop s in r.GetStopArray(r.GetFirstCross()))
                {
                    //s.Chosen = false;
                    s.Chosenchosen = false;
                }
            }
            foreach (IRoad r in currmodel.GetModelSettings().Roads())
            {
                foreach (IStop s in r.GetStopArray(r.GetFirstCross()))
                {
                    if (s.Chosen)
                    {
                        foreach (IPassenger pp in s.Passengers)
                        {

                            pp.destination.Chosenchosen = true;

                        }
                    }
                }
            }
        }

        static void PaintVehicles()
        {
            int dirsign;
            foreach (Road r in currmodel.GetModelSettings().Roads())
            {
                Cross temp1 = (Cross)r.GetFirstCross();
                Cross temp2 = (Cross)r.GetSecondCross();
                IVehicle[] vehicles = r.GetVehicles();
                Color chosencolor = Color.Red;
                for (int i = 0; i < vehicles.Length; i++)
                {
                    dirsign = (vehicles[i].Destination == temp2) ? -1 : 1;
                    vehicles[i].GraphicPosX = (int)(temp1.GetPositionX() + (vehicles[i].Position / r.GetLength()) * (temp2.GetPositionX() - temp1.GetPositionX()));
                    vehicles[i].GraphicPosY = (int)(temp1.GetPositionY() + (vehicles[i].Position / r.GetLength()) * (temp2.GetPositionY() - temp1.GetPositionY()));
                    Point point3 = new Point(
                        vehicles[i].GraphicPosX + 
                        (dirsign)*Math.Sign(r.DirectionY)
                        *(int)(roadSize*2 / 7 * Math.Abs(r.DirectionY)),
                        vehicles[i].GraphicPosY -
                        (dirsign)*Math.Sign(r.DirectionX) 
                        * (int)(roadSize*2 / 7 * Math.Abs(r.DirectionX)));
                    //gr.DrawEllipse(new Pen(vehicleColor, vehicleSize), vehicles[i].GraphicPosX, vehicles[i].GraphicPosY, VehicleSize + 1, vehicleSize + 1);
                    if (vehicles[i].Chosen)
                    { gr.DrawLine(new Pen(chosencolor, vehicleSize), point3, new Point((int)(point3.X + dirsign * _Constants._vehiclelength * r.DirectionX), (int)(point3.Y + dirsign * (_Constants._vehiclelength * r.DirectionY)))); }
                    else 
                    gr.DrawLine(new Pen(ColorSc.VehicleColor, vehicleSize), point3, new Point((int)(point3.X + dirsign*_Constants._vehiclelength*r.DirectionX), (int)(point3.Y + dirsign*(_Constants._vehiclelength*r.DirectionY) )));
                    gr.DrawEllipse(new Pen(Color.Aquamarine, 2), point3.X, point3.Y,  2,  2);

                    if (vehicleText)
                        gr.DrawString(vehicles[i].PassCount().ToString(), new Font("Arial", 12), new SolidBrush(Color.Silver), point3, null);
                }
            }
        }
        static void PaintStops()
        {
            foreach (Road r in currmodel.GetModelSettings().Roads())
            {
                Cross temp1 = (Cross)r.GetFirstCross();
                Cross temp2 = (Cross)r.GetSecondCross();
                foreach (IStop s in r.GetStopArray(temp1))
                    if (s!=null)
                {
                    s.GraphicPosX = (int)(temp1.GetPositionX() + (s.Distance / r.GetLength()) * (temp2.GetPositionX() - temp1.GetPositionX()));
                    s.GraphicPosY = (int)(temp1.GetPositionY() + (s.Distance / r.GetLength()) * (temp2.GetPositionY() - temp1.GetPositionY()));
                    Point point3 = new Point(10 + s.GraphicPosX, s.GraphicPosY);
                    //gr.DrawEllipse(new Pen(stopColor, stopSize), s.GraphicPosX - 1, s.GraphicPosY - 1, stopSize + 1, stopSize + 1);
                   
                    if (s.Chosen)
                        gr.DrawLine(new Pen(ColorSc.Chosencolor, (int)(RoadSize)), new Point((int)(point3.X - r.DirectionX * stopSize), (int)(point3.Y - r.DirectionY * stopSize)), new Point((int)(point3.X + r.DirectionX * stopSize), (int)(point3.Y + r.DirectionY * stopSize)));
                    else
                        if (s.Chosenchosen)
                            gr.DrawLine(new Pen(ColorSc.Chosenchosencolor, (int)(RoadSize)), new Point((int)(point3.X - r.DirectionX * stopSize), (int)(point3.Y - r.DirectionY * stopSize)), new Point((int)(point3.X + r.DirectionX * stopSize), (int)(point3.Y + r.DirectionY * stopSize)));

                        else

                    gr.DrawLine(new Pen(ColorSc.StopColor, (int)(RoadSize)), new Point((int)(point3.X - r.DirectionX * stopSize), (int)(point3.Y - r.DirectionY * stopSize)), new Point((int)(point3.X + r.DirectionX * stopSize), (int)(point3.Y + r.DirectionY * stopSize)));
            gr.DrawEllipse(new Pen(ColorSc.Chosencolor, (int)1), (int)(point3.X - r.DirectionX * stopSize), (int)(point3.Y - r.DirectionY * stopSize), 1, 1);
                    //gr.DrawString(s.PassCount().ToString(), new Font("Arial", 12), new SolidBrush(Color.Black), new Point(point3.X + (int)(r.DirectionY*RoadSize), point3.Y + (int) (r.DirectionX*RoadSize)), null);
                    if(busStopText)
                        gr.DrawString(s.PassCount().ToString(), new Font("Arial", 12), new SolidBrush(Color.Black), new Point(point3.X - stopSize,point3.Y - stopSize), null);

                }
            }
        }
        static void PaintCrosses()
        {
            foreach (Cross c in currmodel.GetModelSettings().Crosses())
            {
                Point point1 = new Point((int)c.GetPositionX() - 10, (int)c.GetPositionY() - 10);
                Point point2 = new Point((int)c.GetPositionX() + 10, (int)c.GetPositionY() + 10);
                gr.DrawEllipse(new Pen(ColorSc.CrossColor, crossSize),
                    (int)(c.GetPositionX() - crossSize/2 ),
                    (int)(c.GetPositionY() - crossSize/2 ), crossSize, crossSize);
                if (c.Chosen)
                {
                    gr.DrawEllipse(new Pen(ColorSc.Chosencolor, (int)(crossSize / 4)),
                    (int)(c.GetPositionX() - crossSize ),
                    (int)(c.GetPositionY() - crossSize ), crossSize*2, crossSize*2);
                }
            }
        }
        static void PaintRoads()
        {
            //gr.FillRectangle(new SolidBrush(backgroundColor), new Rectangle(0, 0, 400, 400));
            foreach (Road r in currmodel.GetModelSettings().Roads())
            {
                Cross temp1 = (Cross)r.GetFirstCross();
                Cross temp2 = (Cross)r.GetSecondCross();
                Point point1 = new Point((int)temp1.GetPositionX(), (int)temp1.GetPositionY());
                Point point2 = new Point((int)temp2.GetPositionX(), (int)temp2.GetPositionY());
                
                gr.DrawLine(new Pen(ColorSc.RoadColor, roadSize), point1, point2);
                if (r.Chosen)
                    gr.DrawLine(new Pen(ColorSc.Chosencolor, (int)(roadSize / 3)), point1, point2);
                else if (r.Chosenchosen)
                    gr.DrawLine(new Pen(ColorSc.Chosenchosencolor, (int)(roadSize / 3)), point1, point2);

            }

        }
        static public void PaintEverything()
        {
            gr.FillRectangle(new SolidBrush(ColorSc.BackgroundColor), new Rectangle(0, 0, 1000, 1000));
            //gr.DrawRectangle(new Pen(Color.DarkBlue, 3), 0, 0, 1000, 1000);
            PaintStops();
            PaintRoads();
            PaintCrosses();
            PaintStops();
            PaintVehicles();
            grout.FillRectangle(new SolidBrush(Color.DarkBlue), 0, 0, Xs, 600);
            grout.FillRectangle(new SolidBrush(Color.DarkBlue), 0, 0, 800, Ys);
            grout.FillRectangle(new SolidBrush(Color.DarkBlue), Xs + 1000, 0, 800, 600);
            grout.FillRectangle(new SolidBrush(Color.DarkBlue), 0, Ys + 1000, 800, 600);
            grout.DrawImage(bitmap, Xs, Ys);

        }
        static public void PaintEverythingOlder()
        {
            gr.FillRectangle(new SolidBrush(ColorSc.BackgroundColor), new Rectangle(0, 0, 400, 400));
            //gr.DrawLine(new Pen(Color.Black, 12), new Point(10, 10), new Point(100, 100));

            foreach (Road r in currmodel.GetModelSettings().Roads())
            {
                Cross temp1 = (Cross)r.GetFirstCross();
                Cross temp2 = (Cross)r.GetSecondCross();
                Point point1 = new Point((int)temp1.GetPositionX(), (int)temp1.GetPositionY());
                Point point2 = new Point((int)temp2.GetPositionX(), (int)temp2.GetPositionY());

                gr.DrawLine(new Pen(roadColor, roadSize), point1, point2);
                foreach (IStop s in r.GetStopArray(temp1))
                {
                    s.GraphicPosX=(int)(temp1.GetPositionX() + (s.Distance / r.GetLength()) * (temp2.GetPositionX() - temp1.GetPositionX()));
                    s.GraphicPosY=(int)(temp1.GetPositionY() + (s.Distance / r.GetLength()) * (temp2.GetPositionY() - temp1.GetPositionY()));
                    Point point3 = new Point(10 + s.GraphicPosX, s.GraphicPosY);
                    gr.DrawEllipse(new Pen(stopColor, stopSize), s.GraphicPosX-1, s.GraphicPosY-1, stopSize+1, stopSize+1);
                    gr.DrawString(s.PassCount().ToString(), new Font("Arial", 12), new SolidBrush(Color.Black), point3, null);
                }
                // IVehicle[] vehicles = r.GetVehicles();
                // for (int i = 0; i < vehicles.Length; i++)
                // {
                //   gr.DrawEllipse(new Pen(Color.Red, 5), (int)temp1.GetPositionX() + vehicles[i].Position, (int)temp1.GetPositionY() + vehicles[i].Position, 6, 6);
                // }
            }

            foreach (Cross c in currmodel.GetModelSettings().Crosses())
            {


                Point point1 = new Point((int)c.GetPositionX() - 10, (int)c.GetPositionY() - 10);
                Point point2 = new Point((int)c.GetPositionX() + 10, (int)c.GetPositionY() + 10);
                gr.DrawEllipse(new Pen(crossColor, crossSize), (int)(c.GetPositionX() - crossSize/2), (int)(c.GetPositionY() - crossSize/2), crossSize, crossSize);


            }



            foreach (Road r in currmodel.GetModelSettings().Roads())
            {
                Cross temp1 = (Cross)r.GetFirstCross();
                Cross temp2 = (Cross)r.GetSecondCross();
                IVehicle[] vehicles = r.GetVehicles();
                for (int i = 0; i < vehicles.Length; i++)
                {
                    vehicles[i].GraphicPosX=(int)(temp1.GetPositionX() + (vehicles[i].Position / r.GetLength()) * (temp2.GetPositionX() - temp1.GetPositionX()));
                    vehicles[i].GraphicPosY=(int)(temp1.GetPositionY() + (vehicles[i].Position / r.GetLength()) * (temp2.GetPositionY() - temp1.GetPositionY()));
                    Point point3 = new Point(vehicles[i].GraphicPosX, vehicles[i].GraphicPosY);
                    gr.DrawEllipse(new Pen(vehicleColor, vehicleSize), vehicles[i].GraphicPosX,vehicles[i].GraphicPosY , VehicleSize+1, vehicleSize+1);
                    gr.DrawString(vehicles[i].PassCount().ToString(), new Font("Arial", 12), new SolidBrush(Color.Silver), point3, null);
                }
            }


            grout.DrawImage(bitmap, 0.0F, 0.0F);
            
        }

    }
}